package com.burst.reptile.modular.app.controller;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.burst.reptile.common.constant.Constants;
import com.burst.reptile.common.constant.HttpStatus;
import com.burst.reptile.common.exception.CustomException;
import com.burst.reptile.common.exception.user.CaptchaException;
import com.burst.reptile.common.exception.user.CaptchaExpireException;
import com.burst.reptile.common.utils.MessageUtils;
import com.burst.reptile.common.utils.SecurityUtils;
import com.burst.reptile.common.utils.ServletUtils;
import com.burst.reptile.common.utils.ToolUtil;
import com.burst.reptile.common.utils.ip.AddressUtils;
import com.burst.reptile.common.utils.ip.IpUtils;
import com.burst.reptile.framework.config.WxMaConfiguration;
import com.burst.reptile.framework.constant.ConstantFactory;
import com.burst.reptile.framework.manager.AsyncManager;
import com.burst.reptile.framework.manager.factory.AsyncFactory;
import com.burst.reptile.framework.redis.RedisCache;
import com.burst.reptile.framework.security.LoginBody;
import com.burst.reptile.framework.security.LoginUser;
import com.burst.reptile.framework.security.service.TokenService;
import com.burst.reptile.framework.web.result.Result;
import com.burst.reptile.modular.system.entity.SysUser;
import com.burst.reptile.modular.system.service.ISysUserService;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;

/**
 * 微信小程序用户接口
 * 
 * @author wujin
 *
 * @date: 2020-8-5 14:32:25
 */
@RestController
@RequestMapping("/wx/user/{appid}")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WxMaUserController {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private final ISysUserService userService;

	private final RedisCache redisCache;

	private final TokenService tokenService;

	/**
	 * 登陆接口
	 */
	@GetMapping("/login")
	public Result<Object> login(@PathVariable String appid, String code) {
		if (StringUtils.isBlank(code)) {
			return Result.error("empty jscode");
		}

		final WxMaService wxService = WxMaConfiguration.getMaService(appid);

		try {
			WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
			this.logger.info(session.getSessionKey());
			this.logger.info(session.getOpenid());
			return Result.success(session);
		} catch (WxErrorException e) {
			this.logger.error(e.getMessage(), e);
			return Result.error(e.toString());
		}
	}

	/**
	 * 短信验证码登录
	 */
	@PostMapping("/codephone")
	public Result<Object> phonelogin(@Validated @RequestBody LoginBody loginBody, @PathVariable String appid) {
		String username = loginBody.getUsername();
		String code = loginBody.getCode();
		String verifyKey = Constants.CAPTCHA_CODE_KEY + loginBody.getUuid();
		String captcha = redisCache.getCacheObject(verifyKey);
		redisCache.deleteObject(verifyKey);
		if (captcha == null) {
			AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
					MessageUtils.message("user.jcaptcha.expire")));
			throw new CaptchaExpireException();
		}
		if (!code.equalsIgnoreCase(captcha)) {
			AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
					MessageUtils.message("user.jcaptcha.error")));
			throw new CaptchaException();
		}
		// 生成令牌
		SysUser user = userService.selectUserByUserName(username);
		if (ToolUtil.isEmpty(user)) { // 为空则注册
			user = new SysUser();
			// 头像
			user.setAvatar(Constants.DEFAULT_AVATAR);
			// 昵称
			user.setNickName("用户" + username.substring(username.length() - 6));
			// 手机号
			user.setPhonenumber(username);
			// 用户类型
			user.setUserType("11");
			user.setUserName(username);
			// 获取粉丝量
			user.setFans("0");
			// 获取关注量
			user.setFollow("0");
			// 获取点赞量
			user.setLike("0");
			// 获取发布量
			user.setReleaseVolume("0");
			// 收藏量
			user.setCollection("0");
			userService.insertUser(user);

		} else {
			Long userId = user.getUserId();
			// 获取粉丝量
			user.setFans(ConstantFactory.me().getFans(userId));
			// 获取关注量
			user.setFollow(ConstantFactory.me().getAttention(userId));
			// 获取点赞量
			user.setLike(ConstantFactory.me().getLikes(userId));
			// 获取发布量
			user.setReleaseVolume(ConstantFactory.me().getReleaseVolume(userId));
			// 收藏量
			user.setCollection(ConstantFactory.me().getCollects(userId));
		}
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS,
				MessageUtils.message("user.login.success")));
		LoginUser loginUser = new LoginUser(user, null);
		String objectId = IdUtil.objectId();
		Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":*");
		if(ToolUtil.isNotEmpty(keys)) {
			keys.forEach(i -> {
				redisCache.deleteObject(i);
			});
		}
		redisCache.setCacheObject(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":" + objectId, loginUser);
		Map<String, Object> map = new HashMap<>();
		map.put("token", user.getUserId() + ":" + objectId);
		map.put("user", user);
		return Result.success(map);
	}

	/**
	 * 手机密码登录
	 */
	@PostMapping("/pwdphone")
	public Result<Object> pwdphone(@Validated @RequestBody LoginBody loginBody, @PathVariable String appid) {
		String username = loginBody.getUsername();
		String password = loginBody.getPassword();
		// 生成令牌
		SysUser user = userService.selectUserByUserName(username);
		if (ToolUtil.isEmpty(user)) { // 为空则注册
			AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户不存在"));
			throw new CustomException("用户不存在");
		} else {
			boolean matchesPassword = SecurityUtils.matchesPassword(password, user.getPassword());
			if (!matchesPassword) {
				AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "密码不正确"));
				throw new CustomException("密码不正确，请重新输入");
			}
			Long userId = user.getUserId();
			// 获取粉丝量
			user.setFans(ConstantFactory.me().getFans(userId));
			// 获取关注量
			user.setFollow(ConstantFactory.me().getAttention(userId));
			// 获取点赞量
			user.setLike(ConstantFactory.me().getLikes(userId));
			// 获取发布量
			user.setReleaseVolume(ConstantFactory.me().getReleaseVolume(userId));
			// 收藏量
			user.setCollection(ConstantFactory.me().getCollects(userId));
		}
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS,
				MessageUtils.message("user.login.success")));
		LoginUser loginUser = new LoginUser(user, null);
		String objectId = IdUtil.objectId();
		Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":*");
		if(ToolUtil.isNotEmpty(keys)) {
			keys.forEach(i -> {
				redisCache.deleteObject(i);
			});
		}
		redisCache.setCacheObject(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":" + objectId, loginUser);
		Map<String, Object> map = new HashMap<>();
		map.put("token", user.getUserId() + ":" + objectId);
		map.put("user", user);
		return Result.success(map);
	}

	/**
	 * <pre>
	 * 获取用户信息接口
	 * </pre>
	 */
	@GetMapping("/info")
	public Result<Object> info(@PathVariable String appid, String sessionKey, String signature, String rawData,
			String encryptedData, String iv) {
		final WxMaService wxService = WxMaConfiguration.getMaService(appid);

		// 用户信息校验
		if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
			return Result.error("user check failed");
		}

		// 解密用户信息
		WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);

		return Result.success(userInfo);
	}

	/**
	 * <pre>
	 * 获取用户绑定手机号信息
	 * </pre>
	 */
	@GetMapping("/phone")
	public Result<Object> phone(@PathVariable String appid, String sessionKey, String signature, String rawData,
			String encryptedData, String iv) {
		final WxMaService wxService = WxMaConfiguration.getMaService(appid);
		WxMaUserService wxUserService = wxService.getUserService();
		
		// 用户信息校验
		if (!wxUserService.checkUserInfo(sessionKey, rawData, signature)) {
			return Result.error("user check failed");
		}
		// 解密
		WxMaPhoneNumberInfo phoneNoInfo = wxUserService.getPhoneNoInfo(sessionKey, encryptedData, iv);

		SysUser user = userService.selectUserByUserName(phoneNoInfo.getPhoneNumber());
		if (ToolUtil.isEmpty(user)) { // 为空则注册
			WxMaUserInfo userInfo = JSONObject.parseObject(rawData, WxMaUserInfo.class);
			user = new SysUser();
			// 头像
			user.setAvatar(userInfo.getAvatarUrl());
			// 昵称
			user.setNickName(userInfo.getNickName());
			// 手机号
			user.setPhonenumber(phoneNoInfo.getPhoneNumber());
			// 用户类型
			user.setUserType("11");
			String gender = userInfo.getGender();
			if (StrUtil.isNotEmpty(gender)) {
				user.setSex(gender);
			}
			user.setUserName(phoneNoInfo.getPhoneNumber());
			// 获取粉丝量
			user.setFans("0");
			// 获取关注量
			user.setFollow("0");
			// 获取点赞量
			user.setLike("0");
			// 获取发布量
			user.setReleaseVolume("0");
			// 收藏量
			user.setCollection("0");
			userService.insertUser(user);

		} else {
			Long userId = user.getUserId();
			// 获取粉丝量
			user.setFans(ConstantFactory.me().getFans(userId));
			// 获取关注量
			user.setFollow(ConstantFactory.me().getAttention(userId));
			// 获取点赞量
			user.setLike(ConstantFactory.me().getLikes(userId));
			// 获取发布量
			user.setReleaseVolume(ConstantFactory.me().getReleaseVolume(userId));
			// 收藏量
			user.setCollection(ConstantFactory.me().getCollects(userId));
			// 草稿箱数量
			user.setDraftsNum(ConstantFactory.me().getDraftsNum(userId));
		}
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNoInfo.getPhoneNumber(), Constants.LOGIN_SUCCESS,
				MessageUtils.message("user.login.success")));
		LoginUser loginUser = new LoginUser(user, null);
		UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
		String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
		if (ToolUtil.isNotEmpty(userAgent)) {
			// 获取客户端操作系统
			String os = userAgent.getOs().getName();
			// 获取客户端浏览器
			String browser = userAgent.getBrowser().getName();
			loginUser.setBrowser(browser);
			loginUser.setOs(os);
		}
		loginUser.setIpaddr(ip);
		String address = AddressUtils.getRealAddressByIP(ip);
		loginUser.setLoginLocation(address);
		loginUser.setLoginTime(System.currentTimeMillis());
		String objectId = IdUtil.objectId();
		Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":*");
		if(ToolUtil.isNotEmpty(keys)) {
			keys.forEach(i -> {
				redisCache.deleteObject(i);
			});
		}
		redisCache.setCacheObject(Constants.LOGIN_TOKEN_KEY + user.getUserId() + ":" + objectId, loginUser);
		Map<String, Object> map = new HashMap<>();
		map.put("token", user.getUserId() + ":" + objectId);
		map.put("user", user);
		return Result.success(map);
	}

	/**
	 * 获取用户信息
	 * 
	 * @return
	 */
	@GetMapping("/getUserInfo")
	public Result<Object> getUserInfo() {
		LoginUser loginUser = tokenService.getWxUser();
		if (ToolUtil.isEmpty(loginUser)) {
			throw new CustomException("未登录", HttpStatus.UNAUTHORIZED);
		}
		return Result.success(loginUser);
	}

	/**
	 * 退出登录
	 * 
	 * @return
	 */
	@GetMapping("/logout")
	public Result<Object> logout(HttpServletRequest request) {
		String token = request.getHeader(Constants.TOKEN);
		LoginUser loginUser = tokenService.getWxUser();
		if(ToolUtil.isNotEmpty(loginUser)) {
			redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + token);
		}
		return Result.success("ok");
	}
}
